package com.example.chat.service.impl;

import com.dragonsoftbravo.libs.JWTHelper;
import com.example.chat.constant.SystemConstant;
import com.example.chat.model.vo.TokenInfoVo;
import com.example.chat.service.JwtService;
import com.example.chat.utils.DOAException;
import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.Objects;

@Slf4j
@Service
public class JwtServiceImpl implements JwtService {

    /**
     * 私钥
     */
    private RSAPrivateKey privateKey;

    /**
     * 公钥
     */
    private RSAPublicKey publicKey;

    /**
     * 自动载入密钥
     */
    @PostConstruct
    public void loadPrivateKey() {

        Try.run(() -> {
            KeyFactory kf = KeyFactory.getInstance("RSA");

            //识别证书，获取密钥
            byte[] privateBytes = IOUtils.toByteArray(Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream("rsa/private_key.der")));
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateBytes);
            privateKey = (RSAPrivateKey) kf.generatePrivate(spec);
            //识别证书，获取公钥
            byte[] publicBytes = IOUtils.toByteArray(Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream("rsa/public_key.der")));
            X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(publicBytes);
            publicKey = (RSAPublicKey) kf.generatePublic(pubSpec);

            log.debug("Finish load RSA certs files");
        }).onFailure(e -> log.error(this.getClass().getSimpleName(), e));


    }

    @Override
    public String getToken(TokenInfoVo tokenInfoVo) {
        //过期时间为10小时
        Date expDate = DateUtils.addWeeks(new Date(), 1);
        JWTHelper jwtHelper = JWTHelper.instance().setPrivateKey(this.privateKey).setPublicKey(this.publicKey)
                .withExpDate(expDate).withBodyJson(SystemConstant.JWT_FILED_NAME, tokenInfoVo);
        return jwtHelper.headlessSignRsa256();
    }

    @Override
    public TokenInfoVo unSignToken(String token) {
        return Try.of(()->{
            JWTHelper helper = JWTHelper.instance().setPrivateKey(this.privateKey).setPublicKey(this.publicKey)
                    .setEncryptedClaim(false);
            return helper.headlessLoadObjClaimRs256(token, SystemConstant.JWT_FILED_NAME, TokenInfoVo.class);
        }).onFailure(e->log.error(e.getClass().getSimpleName(), e)).getOrElseThrow(()->new DOAException("508", "请登录"));
    }

    @Override
    public String signAppAssetToken(String appAssetCode) {
        JWTHelper jwtHelper = JWTHelper.instance().setPrivateKey(this.privateKey).setPublicKey(this.publicKey)
                .withBodyJson(SystemConstant.JWT_APP_ASSET_NAME, appAssetCode);
        return jwtHelper.headlessSignRsa256();
    }

    @Override
    public String unSignAppAssetToken(String token) {
        return Try.of(()->{
            JWTHelper helper = JWTHelper.instance().setPrivateKey(this.privateKey).setPublicKey(this.publicKey)
                    .setEncryptedClaim(false);
            return helper.headlessLoadObjClaimRs256(token, SystemConstant.JWT_APP_ASSET_NAME, String.class);
        }).onFailure(e->log.error(e.getClass().getSimpleName(), e)).getOrElseThrow(()->new DOAException("508", "请登录"));
    }
}
